package xiaoa.java.es.client;


import java.util.Date;



import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.xcontent.XContentBuilder;

import com.alibaba.fastjson.JSON;

import xiaoa.java.es.bean.IGroupResult;
import xiaoa.java.es.bean.PaginationSupport;
import xiaoa.java.es.bean.Params;
import xiaoa.java.log.L;

/**
 * es 操作工具类
 * @author lkc
 * @date 2017年11月10日 下午2:53:26
 * @version V1.0
 *
 */
public abstract class EsClient {
	
	/**
	 * 客户端工具类
	 */
	private  TransportClient[] cllients = new TransportClient[0];
	
	
	/**
	 * 客户端map
	 */
	private Map<String, TransportClient>   clientMap = new HashMap<>();
	
	/**
	 * config
	 */
	private Map<Integer, EsServerConfig>  configMap = new HashMap<>();
	
	
	protected static final String GROUPNAME = "TitleHs";// 聚合字段
	protected static final String PARENTARRNAME = "top";// 构建聚合父名称
	protected static final String CHILDARRNAME = "topchild";// 构建聚合子名称
	
	
	/**
	 * 获取config
	 * @Title: getConfig
	 * @param id
	 * @return
	 * @author lkc
	 */
	private EsServerConfig getConfig(int id){
		
		return configMap.get(id);
		
	}

	
	/**
	 * config
	 * @Title: addConfigList
	 * @param config
	 * @author lkc
	 */
	public void addConfigList(List<EsServerConfig> configList)throws Exception{
		
		if (configList == null || configList.size() == 0){
		    throw new RuntimeException(" configList is empty");
		}
		
		for (EsServerConfig  config : configList){
			
			if (config == null){
				continue;
			}
			
			int id = config.getKey();
			
			// 添加到map
			configMap.put(id, config);
			
			if (!config.isLazy()){
				initClient(config);
			}
			
		}
		
	}


	/**
	 * 获取客户端如果没有初始化客户端
	 * @Title: getClientOrInit
	 * @param host
	 * @param id
	 * @return
	 * @author lkc
	 */
	public TransportClient  getClient(Integer id)throws Exception{
		
		if (id > 1000){
			throw new RuntimeException(" id is to big");
		}
		
		if (cllients.length  >  id && cllients[id] != null ){
			return cllients[id];
		}
		
		// 获取配置
		EsServerConfig config = getConfig(id);
		
		if (config == null ){
			throw new RuntimeException(" not find id " + id);
		}
		
		// 初始化服务器
		initClient(config);
		
		return cllients[id];
	}
	
	
	/**
	 * 初始化客户端
	 * @Title: initClient
	 * @param config
	 * @author lkc
	 */
	public void initClient(EsServerConfig config)throws Exception{
		
		synchronized (cllients) {
			
			int id = config.getKey();
			
			// 如果已经被初始化
			if (cllients.length  >  id && cllients[id] != null ){
				return ;
			}
			
			if (cllients.length <= id){
				
				 TransportClient[] tempCllients = new  TransportClient[id+1];
				 System.arraycopy(cllients, 0, tempCllients, 0, cllients.length);
				 cllients =  tempCllients ;
			}
			
			// key
			String key = config.getHost() + ":" + config.getPort() + "/" + config.getClusterName();
			TransportClient  client =  clientMap.get(key);
			
			if (client != null){
				cllients[id] = client;
				return ;
			}
			
			
			long startTime = System.currentTimeMillis();
			LinkedHashMap<String, Object>  logMap = new LinkedHashMap<>();
			
			// 创建客户端
			client = createClient(config);
			
			if (client == null){
				throw new RuntimeException(" createClient return null ");
			}
			
			logMap.put("succ", client != null);
			logMap.put("key", key);
			L.showUsedTime("createClient", logMap, startTime, System.currentTimeMillis());
			
			// 设置客户端
			cllients[id] = client;
			clientMap.put(key, client);
			
		}
		
	}
	
	
	/**
	 * 获取分片
	 * @Title: getSearchIndex
	 * @param params
	 * @return
	 * @author lkc
	 */
	public  String[] getSearchIndex(Params params) {

		String[] indexs = getConfig(params.getSearchEngineType()).indexs(params);
		
		LinkedHashMap<String, Object>  logMap = new LinkedHashMap<>();
		
		logMap.put("indexs", JSON.toJSONString(indexs));
		
		EsClient.info("searchIndex", logMap);
		
		return indexs;
	}
	
	
	
	/**
	 * 是否是debug
	 * @Title: isDebug
	 * @return
	 * @author lkc
	 */
	protected boolean isDebug(){
		return false;
	}
	
	/**
	 * 日志
	 * @Title: info
	 * @param logMap
	 * @author lkc
	 */
	public static  void info(String function,LinkedHashMap<String, Object>  logMap){
		
		if (logMap != null){
			L.info(function, logMap);
		}
	}
	
	/**
	 * 打印query
	 * @Title: infoQuery
	 * @param str
	 * @author xiaoa
	 */
     public static void infoQuery(String str){
		
		if (str != null){
			L.info(str);
		}
	}
	
	/**
	 * debug
	 * @Title: debug
	 * @param logMap
	 * @author lkc
	 */
    protected  void debug(String function,LinkedHashMap<String, Object>  logMap){
    	if (logMap != null){
    		
    		System.out.println(function + ":" + JSON.toJSONString(logMap));
    		
//			MeUtils.info(function, logMap);
		}
	}
	
	
	/**
	 * 创建客户端
	 * @Title: createClient
	 * @param config
	 * @return
	 * @throws Exception
	 * @author lkc
	 */
	protected abstract TransportClient createClient(EsServerConfig config)throws Exception;
	
	
	
	/**
	 * 普通搜索，不允许合并
	 * @Title: search
	 * @param searchCondition
	 * @param page
	 * @param pageSize
	 * @param minCount
	 * @return
	 * @throws Exception
	 * @author lkc
	 */
	public abstract <R> PaginationSupport<R>  searchList(Params params,int page,int pageSize , Class<R> resultCla)throws Exception;
	
	
	/**
	 * 合并搜索
	 * @Title: searchGroup
	 * @param searchCondition
	 * @param page
	 * @param pageSize
	 * @param minCount
	 * @return
	 * @throws Exception
	 * @author lkc
	 */
	public abstract <R> PaginationSupport<R>  searchGroup(Params params,int page,int pageSize , Class<R> resultCla)throws Exception;
	
	
	/**
	 * 统计
	 * @Title: stat
	 * @param searchCondition
	 * @param statCondition
	 * @param statCount
	 * @param minCount
	 * @return
	 * @throws Exception
	 * @author lkc
	 */
	public abstract List<IGroupResult>  stat(Params params,int statCount,int minCount)throws Exception; 
	
    
    /**
     * 查询
     * @Title: searchTotal
     * @param searchCondition
     * @return
     * @throws Exception
     * @author lkc
     */
    public abstract long searchTotal(Params params) throws Exception ;
	
    /**
     * 获取最后的索引时间
     * @Title: getLastDateIndexTime
     * @param searchCondition
     * @return
     * @throws Exception
     * @author lkc
     */
    public abstract Date getLastDateIndexTime(Params params)throws Exception;
    
    
    /**
     * 通过游标拉取id
     * @Title: searchByEsForCursorGetId
     * @param searchCondition
     * @param num 数量
     * @return
     * @throws Exception
     * @author lkc
     */
    public abstract <T>  List<T> searchByEsForCursorGetData(Params params, long num , Class<T> returnClass) throws Exception ;
    
    
    /**
     * 通过游标拉取ID
     * @Title: searchByEsForCursorGetData
     * @param searchCondition
     * @param returnClass
     * @return
     * @throws Exception
     * @author lkc
     */
    public abstract <T>  List<T> searchByEsForCursorGetData(Params params , Class<T> returnClass) throws Exception ;

    
	
	/**
	 * 修改文档
	 * @Title: updateDataForEs
	 * @param searchCondition
	 * @param id
	 * @param dataBuilder
	 * @return
	 * @throws Exception
	 * @author lkc
	 */
    public abstract boolean updateDataForEs(Params params, String id , XContentBuilder dataBuilder) throws Exception ;
    
    
	/**
	 * 保存文档
	 * @Title: saveDataForEs
	 * @param searchCondition
	 * @param id
	 * @param dataBuilder
	 * @return
	 * @throws Exception
	 * @author lkc
	 */
    public abstract boolean saveDataForEs(Params params , String id , XContentBuilder dataBuilder) throws Exception ;
    
    /**
     * 获取搜索requesr
     * @Title: getSearchRequest
     * @param params
     * @throws Throwable
     * @author xiaoa
     */
    public abstract SearchRequestBuilder getSearchRequest(Params params)throws Throwable;
    

}
